// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// Copyright (C) 2012	stfour

#include <gccore.h>
#include <ogc/machine/processor.h>
#include <ogcsys.h>
#include <stdio.h>
#include <string.h>

#include "debug.h"


#define EXECUTE_ADDR   ((u8 *) 0x92000000)
#define BOOTER_ADDR    ((u8 *) 0x93000000)
#define ARGS_ADDR      ((u8 *) 0x93200000)
#define HBMAGIC_ADDR   ((u8 *) 0x93200000-8)
#define CMDL_ADDR      ((u8 *) 0x93200000+sizeof(struct __argv))
#define LOADER_SIZE    0x400000
#define LOADER_ADDR    ((u8 *) ARGS_ADDR - LOADER_SIZE)
#define MAXFILESIZE    16777216 // 16mb

extern void __exception_closeall();
typedef void (*entrypoint) (void);
u32 cookie;
void *exeBuffer = (void *) EXECUTE_ADDR;
int directBackToPl = 0;

// this is the booter dump by DIMOK (found in wiiexplorer and usb loader gx)
unsigned char booter_dol[872] = {
	0x7C, 0x60, 0x00, 0xA6, 0x54, 0x63, 0x04, 0x5E, 0x60, 0x63, 0x20, 0x00,
	0x7C, 0x60, 0x01, 0x24, 0x4C, 0x00, 0x01, 0x2C, 0x3C, 0x20, 0x93, 0x01,
	0x38, 0x21, 0x83, 0x80, 0x38, 0x00, 0x00, 0x00, 0x94, 0x01, 0xFF, 0xC0,
	0x3C, 0x60, 0x93, 0x00, 0x38, 0x63, 0x03, 0x68, 0x38, 0x80, 0x00, 0x00,
	0x3C, 0xA0, 0x93, 0x00, 0x38, 0xA5, 0x03, 0x68, 0x7C, 0xA3, 0x28, 0x50,
	0x48, 0x00, 0x02, 0xB1, 0x48, 0x00, 0x02, 0x1C, 0x94, 0x21, 0xFF, 0xE0,
	0x7C, 0x08, 0x02, 0xA6, 0xBF, 0x81, 0x00, 0x10, 0x7C, 0x7D, 0x1B, 0x79,
	0x90, 0x01, 0x00, 0x24, 0x38, 0x60, 0x00, 0x00, 0x41, 0x82, 0x00, 0xE0,
	0x80, 0x7D, 0x00, 0xD8, 0x3C, 0x00, 0x81, 0x7F, 0x60, 0x00, 0xFF, 0xFE,
	0x39, 0x23, 0xFF, 0xFF, 0x7F, 0x89, 0x00, 0x40, 0x41, 0x9D, 0x00, 0x34,
	0x83, 0xFD, 0x00, 0xDC, 0x3D, 0x20, 0x81, 0x80, 0x7C, 0x1F, 0x1A, 0x14,
	0x7F, 0x80, 0x48, 0x40, 0x40, 0x9D, 0x00, 0x08, 0x7F, 0xE3, 0x48, 0x50,
	0x38, 0x80, 0x00, 0x00, 0x7F, 0xE5, 0xFB, 0x78, 0x48, 0x00, 0x02, 0x55,
	0x80, 0x7D, 0x00, 0xD8, 0x7F, 0xE4, 0xFB, 0x78, 0x48, 0x00, 0x02, 0x8D,
	0x7F, 0xBE, 0xEB, 0x78, 0x7F, 0xBF, 0xEB, 0x78, 0x3B, 0x80, 0x00, 0x00,
	0x80, 0xBF, 0x00, 0x90, 0x2F, 0x85, 0x00, 0x00, 0x41, 0x9E, 0x00, 0x28,
	0x80, 0x7F, 0x00, 0x48, 0x2B, 0x83, 0x00, 0xFF, 0x40, 0xBD, 0x00, 0x1C,
	0x80, 0x9F, 0x00, 0x00, 0x7C, 0x9D, 0x22, 0x14, 0x48, 0x00, 0x02, 0x39,
	0x80, 0x7F, 0x00, 0x48, 0x80, 0x9F, 0x00, 0x90, 0x48, 0x00, 0x02, 0x51,
	0x2F, 0x9C, 0x00, 0x06, 0x3B, 0xFF, 0x00, 0x04, 0x3B, 0x9C, 0x00, 0x01,
	0x40, 0x9E, 0xFF, 0xC4, 0x3B, 0xE0, 0x00, 0x00, 0x80, 0xBE, 0x00, 0xAC,
	0x2F, 0x85, 0x00, 0x00, 0x41, 0x9E, 0x00, 0x28, 0x80, 0x7E, 0x00, 0x64,
	0x2B, 0x83, 0x00, 0xFF, 0x40, 0xBD, 0x00, 0x1C, 0x80, 0x9E, 0x00, 0x1C,
	0x7C, 0x9D, 0x22, 0x14, 0x48, 0x00, 0x01, 0xF5, 0x80, 0x7E, 0x00, 0x64,
	0x80, 0x9E, 0x00, 0xAC, 0x48, 0x00, 0x02, 0x0D, 0x2F, 0x9F, 0x00, 0x0A,
	0x3B, 0xDE, 0x00, 0x04, 0x3B, 0xFF, 0x00, 0x01, 0x40, 0x9E, 0xFF, 0xC4,
	0x80, 0x7D, 0x00, 0xE0, 0x80, 0x01, 0x00, 0x24, 0xBB, 0x81, 0x00, 0x10,
	0x38, 0x21, 0x00, 0x20, 0x7C, 0x08, 0x03, 0xA6, 0x4E, 0x80, 0x00, 0x20,
	0x81, 0x23, 0x00, 0x00, 0x3C, 0x00, 0x7F, 0x45, 0x60, 0x00, 0x4C, 0x46,
	0x7F, 0x89, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x40, 0xBE, 0x00, 0x24,
	0xA0, 0x03, 0x00, 0x10, 0x2F, 0x80, 0x00, 0x02, 0x40, 0x9E, 0x00, 0x14,
	0xA0, 0x03, 0x00, 0x12, 0x39, 0x20, 0x00, 0x01, 0x2F, 0x80, 0x00, 0x14,
	0x41, 0xBE, 0x00, 0x08, 0x39, 0x20, 0xFF, 0xFF, 0x7D, 0x23, 0x4B, 0x78,
	0x4E, 0x80, 0x00, 0x20, 0x7C, 0x08, 0x02, 0xA6, 0x94, 0x21, 0xFF, 0xE0,
	0xBF, 0xA1, 0x00, 0x14, 0x7C, 0x7E, 0x1B, 0x78, 0x90, 0x01, 0x00, 0x24,
	0x81, 0x23, 0x00, 0x1C, 0x2F, 0x89, 0x00, 0x00, 0x41, 0x9E, 0x00, 0x98,
	0xA0, 0x03, 0x00, 0x2C, 0x2F, 0x80, 0x00, 0x00, 0x41, 0x9E, 0x00, 0x8C,
	0xA0, 0x03, 0x00, 0x2A, 0x7F, 0xE3, 0x4A, 0x14, 0x3B, 0xA0, 0x00, 0x00,
	0x2F, 0x80, 0x00, 0x20, 0x41, 0x9E, 0x00, 0x58, 0x48, 0x00, 0x00, 0x74,
	0x80, 0x1F, 0x00, 0x00, 0x2F, 0x80, 0x00, 0x01, 0x40, 0xBE, 0x00, 0x44,
	0x80, 0xBF, 0x00, 0x10, 0x80, 0x1F, 0x00, 0x14, 0x81, 0x3F, 0x00, 0x0C,
	0x2F, 0x05, 0x00, 0x00, 0x7F, 0x85, 0x00, 0x40, 0x55, 0x29, 0x00, 0xBE,
	0x65, 0x23, 0x80, 0x00, 0x90, 0x7F, 0x00, 0x0C, 0x41, 0x9D, 0x00, 0x44,
	0x41, 0xBA, 0x00, 0x1C, 0x80, 0x9F, 0x00, 0x04, 0x7C, 0x9E, 0x22, 0x14,
	0x48, 0x00, 0x00, 0xFD, 0x80, 0x7F, 0x00, 0x0C, 0x80, 0x9F, 0x00, 0x14,
	0x48, 0x00, 0x01, 0x15, 0x3B, 0xFF, 0x00, 0x20, 0xA0, 0x1E, 0x00, 0x2C,
	0x7F, 0x9D, 0x00, 0x00, 0x3B, 0xBD, 0x00, 0x01, 0x41, 0x9C, 0xFF, 0xA4,
	0x80, 0x1E, 0x00, 0x18, 0x54, 0x00, 0x00, 0xBE, 0x64, 0x03, 0x80, 0x00,
	0x48, 0x00, 0x00, 0x08, 0x38, 0x60, 0x00, 0x00, 0x80, 0x01, 0x00, 0x24,
	0xBB, 0xA1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x20, 0x7C, 0x08, 0x03, 0xA6,
	0x4E, 0x80, 0x00, 0x20, 0x7C, 0x08, 0x02, 0xA6, 0x94, 0x21, 0xFF, 0xE0,
	0x3C, 0x60, 0x92, 0x00, 0xBF, 0xA1, 0x00, 0x14, 0x90, 0x01, 0x00, 0x24,
	0x4B, 0xFF, 0xFE, 0xE1, 0x2F, 0x83, 0x00, 0x01, 0x40, 0xBE, 0x00, 0x10,
	0x3C, 0x60, 0x92, 0x00, 0x4B, 0xFF, 0xFF, 0x11, 0x48, 0x00, 0x00, 0x0C,
	0x3C, 0x60, 0x92, 0x00, 0x4B, 0xFF, 0xFD, 0xB9, 0x2F, 0x83, 0x00, 0x00,
	0x7C, 0x7F, 0x1B, 0x78, 0x41, 0x9E, 0x00, 0x40, 0x3D, 0x20, 0x93, 0x20,
	0x81, 0x29, 0x00, 0x00, 0x6D, 0x20, 0x5F, 0x61, 0x2F, 0x80, 0x72, 0x67,
	0x40, 0x9E, 0x00, 0x24, 0x3B, 0xA3, 0x00, 0x08, 0x3C, 0x80, 0x93, 0x20,
	0x7F, 0xA3, 0xEB, 0x78, 0x38, 0xA0, 0x00, 0x18, 0x48, 0x00, 0x00, 0x4D,
	0x7F, 0xA3, 0xEB, 0x78, 0x38, 0x80, 0x00, 0x18, 0x48, 0x00, 0x00, 0x65,
	0x7F, 0xE9, 0x03, 0xA6, 0x4E, 0x80, 0x04, 0x21, 0x80, 0x01, 0x00, 0x24,
	0xBB, 0xA1, 0x00, 0x14, 0x38, 0x21, 0x00, 0x20, 0x7C, 0x08, 0x03, 0xA6,
	0x4E, 0x80, 0x00, 0x20, 0x38, 0xA5, 0x00, 0x01, 0x39, 0x20, 0x00, 0x00,
	0x7C, 0xA9, 0x03, 0xA6, 0x48, 0x00, 0x00, 0x0C, 0x7C, 0x89, 0x19, 0xAE,
	0x39, 0x29, 0x00, 0x01, 0x42, 0x00, 0xFF, 0xF8, 0x4E, 0x80, 0x00, 0x20,
	0x38, 0xA5, 0x00, 0x01, 0x39, 0x20, 0x00, 0x00, 0x7C, 0xA9, 0x03, 0xA6,
	0x48, 0x00, 0x00, 0x10, 0x7C, 0x09, 0x20, 0xAE, 0x7C, 0x09, 0x19, 0xAE,
	0x39, 0x29, 0x00, 0x01, 0x42, 0x00, 0xFF, 0xF4, 0x4E, 0x80, 0x00, 0x20,
	0x38, 0x84, 0x00, 0x1F, 0x7C, 0x84, 0x1A, 0x14, 0x54, 0x63, 0x00, 0x34,
	0x54, 0x84, 0x00, 0x34, 0x48, 0x00, 0x00, 0x14, 0x7C, 0x00, 0x18, 0x6C,
	0x7C, 0x00, 0x04, 0xAC, 0x7C, 0x00, 0x1F, 0xAC, 0x38, 0x63, 0x00, 0x20,
	0x7F, 0x83, 0x20, 0x40, 0x41, 0x9C, 0xFF, 0xEC, 0x7C, 0x00, 0x04, 0xAC,
	0x4C, 0x00, 0x01, 0x2C, 0x4E, 0x80, 0x00, 0x20
};

void pl_QueryArgs (int argc, char **argv)
	{
	int i;
	for (i = 0; i < argc; i++)
		if (strcmp(argv[i], "pl") == 0)
			directBackToPl = 1;
	}

int pl_IsDirectBackAvail(void)
	{
	return directBackToPl;
	}

bool pl_BootPostloader (void)
	{
	if (!directBackToPl) return false;

	char *args = "priibooter";
 	struct __argv arg;
	memset (&arg, 0, sizeof(struct __argv));

	arg.argvMagic = ARGV_MAGIC;
	arg.length  = strlen(args) + 1;
	arg.commandLine = (char*)CMDL_ADDR;
	memset (arg.commandLine, 0, arg.length);
	memcpy (arg.commandLine, args, arg.length);

	memcpy(ARGS_ADDR, &arg, sizeof(arg));
	DCFlushRange(ARGS_ADDR, sizeof(arg) + arg.length);

	HBMAGIC_ADDR[0] = 'X';
	HBMAGIC_ADDR[1] = 'X';
	HBMAGIC_ADDR[2] = 'X';
	HBMAGIC_ADDR[3] = 'X';

	memcpy(BOOTER_ADDR, booter_dol, sizeof (booter_dol));
	DCFlushRange(BOOTER_ADDR, sizeof (booter_dol));

	memcpy(EXECUTE_ADDR, LOADER_ADDR, LOADER_SIZE);
	DCFlushRange(EXECUTE_ADDR, LOADER_SIZE);

	entrypoint exeEntryPoint;
	exeEntryPoint = (entrypoint) BOOTER_ADDR;

	gprintf("Booting postLoader...\n");

	/* cleaning up and load dol */
	SYS_ResetSystem(SYS_SHUTDOWN, 0, 0);
	_CPU_ISR_Disable (cookie);
	__exception_closeall ();
	exeEntryPoint ();
	_CPU_ISR_Restore (cookie);

	return true; // make the compiler happy
	}
// stfour/
